#include "threadwork.h"
#include "qdebug.h"
#include "Config/global.h"
#include "DBOperation/mysql.h"
#include "QFile"
#include "QDir"
ThreadWork::ThreadWork(QObject *parent)
    : QThread(parent)
{
    SerialState=InitialSerialPort();
    ppgp1=new PPGRealProcess1();
    ppgp2=new PPGRealProcess2();

    connect(ppgp1,SIGNAL(sendSPOX(double,int)),this,SLOT(getSPOX(double,int)));
    connect(ppgp1,SIGNAL(sendHR(unsigned char,int)),this,SLOT(getHR(unsigned char,int)));
    connect(ppgp1,SIGNAL(sendRR(int,int)),this,SLOT(getRR(int,int)));
    connect(ppgp1,SIGNAL(sendPerfustion(double,int)),this,SLOT(getPerfusion(double,int)));

    connect(ppgp2,SIGNAL(sendSPOX(double,int)),this,SLOT(getSPOX(double,int)));
    connect(ppgp2,SIGNAL(sendHR(unsigned char,int)),this,SLOT(getHR(unsigned char,int)));
    connect(ppgp2,SIGNAL(sendRR(int,int)),this,SLOT(getRR(int,int)));
    connect(ppgp2,SIGNAL(sendPerfustion(double,int)),this,SLOT(getPerfusion(double,int)));
    qDebug()<<"SerialState"<<SerialState;
    if(SerialState)
    {
        connect(qserialPort,SIGNAL(readyRead()),this,SLOT(readComDataSlot()));
    }
    initial();
    SampleNum=0;

}
ThreadWork::~ThreadWork()
{
    delete ppgp1;
    delete ppgp2;

}

void ThreadWork::run()
{
    while (SerialState && RunFlag)
    {
        QByteArray v = gParseQueue.take_front_block();//出队，得到数据在该线程进行处理
        int len=v.size();
        char ff=0xFF;
        char fe=0xFE;
        if(len==242 && v.at(0)==ff && v.at(1)==fe)
        {
            for(int i=0;i<20;i++)
            {
                QByteArray temp_red1, temp_ir1,tempHex_red1,tempHex_ir1;
                QByteArray temp_red2, temp_ir2,tempHex_red2,tempHex_ir2;
                bool OK;
                //第一路
                temp_red1.append(v.at(i*6+2) & 0xFF);//0x3F
                temp_red1.append(v.at(i*6+3));
                temp_red1.append(v.at(i*6+4));
                temp_ir1.append(v.at(i*6+5) & 0xFF);
                temp_ir1.append(v.at(i*6+6));
                temp_ir1.append(v.at(i*6+7));
                tempHex_red1 = temp_red1.toHex();
                tempHex_ir1 = temp_ir1.toHex();
                double red1 = tempHex_red1.toInt(&OK, 16) * 1.2 / 2097152.0;
                double ir1 = tempHex_ir1.toInt(&OK, 16) * 1.2 / 2097152.0;

                //第二路
                temp_red2.append(v.at(i*6+2+120) & 0xFF);
                temp_red2.append(v.at(i*6+3+120));
                temp_red2.append(v.at(i*6+4+120));
                temp_ir2.append(v.at(i*6+5+120) & 0xFF);
                temp_ir2.append(v.at(i*6+6+120));
                temp_ir2.append(v.at(i*6+7+120));
                tempHex_red2 = temp_red2.toHex();
                tempHex_ir2 = temp_ir2.toHex();
                double red2 = tempHex_red2.toInt(&OK, 16) * 1.2 / 2097152.0;//2097152,16777215
                double ir2 = tempHex_ir2.toInt(&OK, 16) * 1.2 / 2097152.0;

                double filterir1=lp_filter_ir1(ir1);
                double filterir2=lp_filter_ir2(ir2);


                double appdata1=getAPPG1(filterir1);
                double appdata2=getAPPG2(filterir2);
                SampleNum++;

                tempPPG2.append(filterir2);
                tempPPG1.append(filterir1);
                if(tempPPG1.size()>1500)
                    tempPPG1.removeFirst();
                if(tempPPG2.size()>1500)
                    tempPPG2.removeFirst();
                if(StartFlag11)
                {
                    if(SampleNum%100==0)
                    {
                        if(Sq(tempPPG1))
                            SigQualityFlag1++;
                        else
                            SigQualityFlag1=0;
                    }
                    if(SigQualityFlag1>3)
                        StartFlag1=true;
                    else
                        StartFlag1=false;
                    if(StartFlag1){
                        ppgp1->StartCompute(ir1,red1);
                        IR1forSave.append(ir1);
                        Red1forSave.append(red1);
//                        tempPPG1.append(filterir1);
                        PPGforAPPG1.append(ir1);
                        p1Num++;
                        if(i%5==0)
                        {
                            int persont=p1Num*100/(MeasureTime*500*60);
                            emit sendProgress2UI(persont,1);
                            if(persont>=100)
                            {
                                saveData1();
                            }
                        }
                    }else
                    {
                        p1Num=0;
                        emit sendProgress2UI(0,1);
                        emit sendSPOX2UI(0,1);
                        emit sendHR2UI(0,1);
                        emit sendRR2UI(0,1);
                        rr1.clear();
                        per_list1.clear();
                        spox_list1.clear();
                    }

                }
                if(StartFlag22)
                {

                    if(SampleNum%100==0)
                    {
                        if(Sq(tempPPG2))
                            SigQualityFlag2++;
                        else
                            SigQualityFlag2=0;
                    }

                    if(SigQualityFlag2>3)
                        StartFlag2=true;
                    else
                        StartFlag2=false;

                    if(StartFlag2){
                        PPGforAPPG2.append(ir2);
                        IR2forSave.append(ir2);
                        Red2forSave.append(red2);
                        ppgp2->StartCompute(ir2,red2);
                        p2Num++;
                        if(i%5==0)
                        {
                            int persont=p2Num*100/(MeasureTime*500*60);
                            emit sendProgress2UI(persont,2);
                            if(persont>=100)
                            {
                                saveData2();
                            }
                        }
                    }else
                    {
                        p2Num=0;
                        emit sendProgress2UI(0,2);
                        emit sendSPOX2UI(0,2);
                        emit sendHR2UI(0,2);
                        emit sendRR2UI(0,2);
                        rr2.clear();
                        per_list2.clear();
                        spox_list2.clear();
                    }
                }
                if(i%5==0)
                {
//                    qDebug()<<"sendData"<<filterir1;
                    emit sendData(filterir1,appdata1,filterir2,appdata2);
                }
            }
        }
    }
    if(SerialState){
        QByteArray b;
        b.append(0x32);
        qserialPort->write(b);
    }
}
/**
 * 信号质量评估
 * @brief ThreadWork::Sq
 * @param ppg
 * @return
 */
bool ThreadWork::Sq(QList<double>ppg)
{
    bool b=true;
    int len=ppg.length();
    int peakNum=0;
    double sum=0;
    if(len>3){
        for(int i=0;i<len-2;i++)
        {
            sum+=ppg.at(i);
            if(ppg.at(i+1)>ppg.at(i) && ppg.at(i+1)>ppg.at(i+2))
                peakNum++;
        }
        sum=sum/(len-2);
        if(peakNum>9 || sum<9)
            b=false;
    }
    b=true;//禁用信号评估
    return b;
}
void ThreadWork::saveData1()
{
    StartFlag1=false;
    StartFlag11=false;
    QList<int>rpos=ppgp1->getPeakPos();
    int* p_data_buf = new int[90000];
    for (int i = 0; i < 90000; i++)
        p_data_buf[i] = 0;
    int j = 0;
    for (int i = 0; i < 90000 ; i++)
    {
        if (i == rpos.at(j)) {
            p_data_buf[i] = 2*(rpos.at(j+1) - rpos.at(j));
            j++;
        }

    }
    if(Constant::SaveRawPPG)
        savetxtfile("D:\\Data\\rpos.txt",rpos);
    hrvDataProcess.setAge(uib1.UserAge.toInt(),uib1.UserSex=="女");
    hrvDataProcess.getSLIndex(rr1,spox_list1,per_list1);
    hrvDataProcess.ComputeHRV(p_data_buf,90000);

    QList<double>sub_ppgForAppg;

    if(Constant::SaveRawPPG){
       QDateTime Time = QDateTime::currentDateTime();
       QString savetime=Time.toString("yyyyMMdd_hhmmss");//格式化时间
       savetxtfile2(QString("D:\\data\\'%1'_'%2'_Channel1.txt").arg(uib1.UserID).arg(savetime),IR1forSave,Red1forSave);
    }
    for(int i=0;i<3000;i++)
    {
        sub_ppgForAppg.append(PPGforAPPG1.at(i));
    }

    QString hrv_res=hrvDataProcess.HRVData2Json(hrvDataProcess.getHRVIndex(),sub_ppgForAppg,uib1);
    if(Constant::SoftWare_Version==1){
        //根据实际填写路径
        QString ParentFolder="D:\\data\\"+uib1.UserID;
        QDir dir(ParentFolder);
        QString fileName;
        if(dir.exists())
        {
            fileName=ParentFolder+".json";
        }else
        {
            bool ok = dir.mkpath(ParentFolder);//创建多级目录
            if(ok)
            {
                fileName=ParentFolder+".json";
            }
        }
        QFile file(fileName);

        if(!file.open(QIODevice::ReadWrite|QIODevice::Text))
        {
            qDebug() << "file error!";
        }
        QTextStream in(&file);
        in << hrv_res;
        file.close();
    }
    delete[] p_data_buf;
    //保存数据库
    QString file=Constant::DataBasePath;
    MySql *mySql = new MySql(file);
    DataBeans dbs;
    qDebug()<<"UserID="<<uib1.UserID;
    dbs.UserID=uib1.UserID;
    dbs.UserName=uib1.UserName;
    dbs.UserAge=uib1.UserAge;
    dbs.UserHeight=uib1.UserHeight;
    dbs.UserWeight=uib1.UserWeight;
    dbs.UserSex=uib1.UserSex;
    dbs.hrvIndexResults=hrv_res;
    dbs.MeasureTime=uib1.MeasureTime;
    mySql->MyInsert(dbs);
    delete mySql;
    if(SingleOrGroup)
        emit sendOver(1);
    else
        emit sendOver2(1);
    StartFlag1=false;
    p1Num=0;


}

void ThreadWork::saveData2()
{
    StartFlag2=false;
    StartFlag22=false;
    QList<int>rpos=ppgp2->getPeakPos();
    int* p_data_buf = new int[90000];
    for (int i = 0; i < 90000; i++)
        p_data_buf[i] = 0;
    int j = 0;
    for (int i = 0; i < 90000 ; i++)
    {
        if (i == rpos.at(j)) {
            p_data_buf[i] = 2*(rpos.at(j+1) - rpos.at(j));
            j++;
        }

    }
    hrvDataProcess.setAge(uib2.UserAge.toInt(),uib2.UserSex=="女");
    hrvDataProcess.getSLIndex(rr2,spox_list2,per_list2);
    hrvDataProcess.ComputeHRV(p_data_buf,90000);

    // if(Constant::SaveRawPPG)
    //     savetxtfile("D:\\Data\\rr2.txt",rr2);
    if(Constant::SaveRawPPG){
        QDateTime Time = QDateTime::currentDateTime();
        QString savetime=Time.toString("yyyyMMdd_hhmmss");//格式化时间
       savetxtfile2(QString("D:\\data\\'%1'_'%2'_Channel2.txt").arg(uib2.UserID).arg(savetime),IR2forSave,Red2forSave);
    }
    QList<double>sub_ppgForAppg;
    for(int i=0;i<3000;i++)
    {
        sub_ppgForAppg.append(PPGforAPPG2.at(i));
    }

    QString hrv_res=hrvDataProcess.HRVData2Json(hrvDataProcess.getHRVIndex(),sub_ppgForAppg,uib2);
    if(Constant::SoftWare_Version==1){
        //根据实际填写路径
        QString ParentFolder="D:\\data\\"+uib2.UserID;
        QDir dir(ParentFolder);
        QString fileName;
        if(dir.exists())
        {
            fileName=ParentFolder+".json";
        }else
        {
            bool ok = dir.mkpath(ParentFolder);//创建多级目录
            if(ok)
            {
                fileName=ParentFolder+".json";
            }
        }
        QFile file(fileName);

        if(!file.open(QIODevice::ReadWrite|QIODevice::Text))
        {
            qDebug() << "file error!";
        }
        QTextStream in(&file);
        in << hrv_res;
        file.close();
    }
    delete[]p_data_buf;

    //保存数据库
    QString file=Constant::DataBasePath;
    MySql *mySql = new MySql(file);
    DataBeans dbs;
    qDebug()<<"UserID="<<uib2.UserID;
    dbs.UserID=uib2.UserID;
    dbs.UserName=uib2.UserName;
    dbs.UserAge=uib2.UserAge;
    dbs.UserHeight=uib2.UserHeight;
    dbs.UserWeight=uib2.UserWeight;
    dbs.UserSex=uib2.UserSex;
    dbs.hrvIndexResults=hrv_res;
    dbs.MeasureTime=uib2.MeasureTime;
    mySql->MyInsert(dbs);
    delete mySql;
    if(SingleOrGroup)
        emit sendOver(2);
    else
        emit sendOver2(2);
}
void ThreadWork::getSPOX(double ox,int p)
{
    emit sendSPOX2UI(ox,p);
    if(p==1)
    {
        spox_list1.append(ox);
    }else if(p==2)
    {
        spox_list2.append(ox);
    }
}
void ThreadWork::getHR(unsigned char hr,int p)
{
    emit sendHR2UI(hr,p);

}
void ThreadWork::getRR(int rr,int p)
{
    emit sendRR2UI(rr,p);
    if(p==1)
    {
        rr1.append(rr);
    }else if(p==2)
    {
        rr2.append(rr);
    }
}
void ThreadWork::getPerfusion(double perfusion,int p)
{
    if(p==1)
    {
        per_list1.append(perfusion);
    }else if(p==2)
    {
        per_list2.append(perfusion);
    }
}
double ThreadWork::lp_filter_ir1(double raw_ir)
{
    double static i1=0;double static i2=0;double static i3=0;
    double static o1=0;double static o2=0;double static o3=0;
    i1 = i2;i2 = i3;i3 = raw_ir;
    o1 = b_ppg_lp[0] * i3 + b_ppg_lp[1] * i2 + b_ppg_lp[2] * i1 - a_ppg_lp[1] * o2 - a_ppg_lp[2] * o3;
    o3 = o2;o2 = o1;
    return o1;
}
double ThreadWork::lp_filter_ir2(double raw_ir)
{
    double static i1=0;double static i2=0;double static i3=0;
    double static o1=0;double static o2=0;double static o3=0;
    i1 = i2;i2 = i3;i3 = raw_ir;
    o1 = b_ppg_lp[0] * i3 + b_ppg_lp[1] * i2 + b_ppg_lp[2] * i1 - a_ppg_lp[1] * o2 - a_ppg_lp[2] * o3;
    o3 = o2;o2 = o1;
    return o1;
}
double ThreadWork::getAPPG1(double raw_ppg)
{
    static double x11 = 0; static double x12 = 0; static double x13 = 0; static double lastdata1 = 0; static double lastdata2 = 0;
    static double y11 = 0; static double y12 = 0; static double y13 = 0;
    static double x21 = 0; static double x22 = 0; static double x23 = 0;
    static double y21 = 0; static double y22 = 0; static double y23 = 0;
    x11 = x12; x12 = x13; x13 = raw_ppg - lastdata1;

    y11 = appg_b1[0] * x13 + appg_b1[1] * x12 + appg_b1[2] * x11 - appg_a1[1] * y12 - appg_a1[2] * y13;
    y13 = y12; y12 = y11; lastdata1 = raw_ppg;

    x21 = x22; x22 = x23; x23 = y11 - lastdata2;
    y21 = appg_b2[0] * x23 + appg_b2[1] * x22 + appg_b2[2] * x21 - appg_a2[1] * y22 - appg_a2[2] * y23;
    y23 = y22; y22 = y21;

    lastdata2 = y11;
    return y21;
}

double ThreadWork::getAPPG2(double raw_ppg)
{
    static double x11 = 0; static double x12 = 0; static double x13 = 0; static double lastdata1 = 0; static double lastdata2 = 0;
    static double y11 = 0; static double y12 = 0; static double y13 = 0;
    static double x21 = 0; static double x22 = 0; static double x23 = 0;
    static double y21 = 0; static double y22 = 0; static double y23 = 0;
    x11 = x12; x12 = x13; x13 = raw_ppg - lastdata1;

    y11 = appg_b1[0] * x13 + appg_b1[1] * x12 + appg_b1[2] * x11 - appg_a1[1] * y12 - appg_a1[2] * y13;
    y13 = y12; y12 = y11; lastdata1 = raw_ppg;

    x21 = x22; x22 = x23; x23 = y11 - lastdata2;
    y21 = appg_b2[0] * x23 + appg_b2[1] * x22 + appg_b2[2] * x21 - appg_a2[1] * y22 - appg_a2[2] * y23;
    y23 = y22; y22 = y21;

    lastdata2 = y11;
    return y21;
}
void ThreadWork::readComDataSlot()
{
    //读取串口数据
    QByteArray readComData = qserialPort->readAll();
//    qDebug()<<"readComData.size="<<readComData.length();
    gParseQueue.push_back(readComData);//入队，如果在这里处理，还是在主线程进行处理
    readComData.clear();
}
void ThreadWork::initial()
{
    IIRDesign(0,2,Constant::SampleRate,2.5,3,a_ppg_lp,b_ppg_lp);//显示用带通0.25hz-3hz
    IIRDesign(0, 2, Constant::SampleRate, 3, 5, appg_a1, appg_b1);//低通
    IIRDesign(0, 2, Constant::SampleRate, 3, 5, appg_a2, appg_b2);//低通



}

void ThreadWork::getUserInfo(UserInfoBeab uib,int p)
{
    if(p==1){
        this->uib1=uib;
        IR1forSave.clear();
        Red1forSave.clear();
    }
    else if(p==2){
        this->uib2=uib;
        IR2forSave.clear();
        Red2forSave.clear();
    }
}

QString ThreadWork::CharArrayToHexString(QByteArray Buffer,int Len)
{
     QString buf;
     for(int i=0;i<Len;i++){
         QString str = QString("%1").arg(Buffer[i]&0xFF,2,16,QLatin1Char('0')).toUpper() + QString("");   //2 字符宽度
         buf += str;
     }
     return buf;
}
void ThreadWork::getStartOrStop(bool b,int p)
{
     SigQualityFlag1=0;
     StartFlag11=b;
     SingleOrGroup=true;
     if(b)
     {
         if(p==1)
         {
            rr1.clear();
            ppgp1->initial();
            p1Num=0;
            spox_list1.clear();
            per_list1.clear();
            PPGforAPPG1.clear();
            IR1forSave.clear();
            Red1forSave.clear();
         }else if(p==2)
         {
            rr2.clear();
            ppgp2->initial();
            p2Num=0;
            spox_list2.clear();
            per_list2.clear();
            PPGforAPPG2.clear();
            IR2forSave.clear();
            Red2forSave.clear();
         }
     }
}
void ThreadWork::getStartOrStop2(bool b,int p)
{
     SingleOrGroup=false;
     if(b)
     {
         if(p==1)
         {
            StartFlag11=true;
            SigQualityFlag1=0;
            rr1.clear();
            ppgp1->initial();
            p1Num=0;
            spox_list1.clear();
            per_list1.clear();
            PPGforAPPG1.clear();
         }else if(p==2)
         {
            StartFlag22=true;
            SigQualityFlag2=0;
            rr2.clear();
            ppgp2->initial();
            p2Num=0;
            spox_list2.clear();
            per_list2.clear();
            PPGforAPPG2.clear();
         }
     }


}
/**
 * @brief MeasureInterface::savetxtfile
 * @param filename
 * @param l
 * 功能：将double型list按照列保存到txt文件中
 */
void ThreadWork::savetxtfile(QString filename,QList<double> l){
     if(filename.isEmpty()){
         qDebug()<<"isEmpty==";
         return;
     }else{
         QFile file(filename);
         if(!file.open(QIODevice::WriteOnly | QIODevice::Text)){
            qDebug()<<"open==";
            return;
         }else{
            QString content;
            for(int i = 0; i < l.length(); i++){
                content += QString::number(l.at(i)) + ",";
            }
            qDebug()<<"content==";
            QTextStream in(&file);
            in << content;
            file.close();
            qDebug()<<"file.close()==";
         }
     }
}
void ThreadWork::savetxtfile(QString filename,QList<int> l){
     if(filename.isEmpty()){
         qDebug()<<"isEmpty==";
         return;
     }else{
         QFile file(filename);
         if(!file.open(QIODevice::WriteOnly | QIODevice::Text)){
            qDebug()<<"open==";
            return;
         }else{
            QString content;
            for(int i = 0; i < l.length(); i++){
                content += QString::number(l.at(i)) + "\r\n";
            }
            qDebug()<<"content==";
            QTextStream in(&file);
            in << content;
            file.close();
            qDebug()<<"file.close()==";
         }
     }
}
void ThreadWork::savetxtfile2(QString filename,QList<double> l1,QList<double> l2){
    if(filename.isEmpty()){
        qDebug()<<"isEmpty==";
        return;
    }else{
        QFile file(filename);
        if(!file.open(QIODevice::WriteOnly | QIODevice::Text)){
            qDebug()<<filename<<"文件打开失败";
            return;
        }else{
            QString content;
            int len1=l1.size();
            int len2=l2.size();
            int len=len1>len2?len2:len1;
            for(int i = 0; i < len; i++){
                content += QString::number(l1.at(i)) + ","+QString::number(l2.at(i))+"\r\n";
            }
            qDebug()<<"content==";
            QTextStream in(&file);
            in << content;
            file.close();
            qDebug()<<"file.close()==";
        }
    }
}
